package com.cmes.core.utils;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 集合相关工具类
 *
 * @author Bruce.Gong
 * @since 1.0.0-SNAPSHOT
 */
public class CollectionUtils {

    /**
     * 判断集合是否为空
     *
     * @param collection 待判断集合
     * @param <T>        集合数据类型
     * @return true | false
     */
    public static <T> boolean isEmpty(Collection<T> collection) {
        return collection == null || collection.isEmpty();
    }

    /**
     * 判断集合是否为空
     *
     * @param map 待判断集合
     * @return true | false
     */
    public static <K, V> boolean isEmpty(Map<K, V> map) {
        return map == null || map.isEmpty();
    }

    /**
     * 判断集合是否不为空
     *
     * @param collection 待判断集合
     * @param <T>        集合数据类型
     * @return true | false
     */
    public static <T> boolean isNotEmpty(Collection<T> collection) {
        return !isEmpty(collection);
    }

    /**
     * 判断集合是否不为空
     *
     * @param map 待判断集合
     * @return true | false
     */
    public static <K, V> boolean isNotEmpty(Map<K, V> map) {
        return !isEmpty(map);
    }

    /**
     * 从集合中取第一个值，如果集合为空，则返回 null
     *
     * @param list 集合
     * @return 集合第一个元素
     */
    public static <T> T firstElement(List<T> list) {
        return isEmpty(list) ? null : list.get(0);
    }

    /**
     * 从集合中取最后一个值，如果集合为空，则返回 null
     *
     * @param list 集合
     * @return 集合最后一个元素
     */
    public static <T> T lastElement(List<T> list) {
        return isEmpty(list) ? null : list.get(list.size() - 1);
    }

    /**
     * 如果集合为空，则返回一个空集合
     *
     * @param collection 集合
     * @param <T>        集合数据类型
     * @return 集合本身或者空集合
     */
    public static <T> List<T> emptyIfNull(List<T> collection) {
        return ifNull(collection, Collections.emptyList());
    }

    /**
     * 如果集合为空，则返回一个默认值
     *
     * @param collection 集合
     * @param def        默认值
     * @param <T>        集合数据类型
     * @return 集合本身或者空集合
     */
    public static <T extends Collection<R>, R> T ifNull(T collection, T def) {
        return isEmpty(collection) ? def : collection;
    }

    /**
     * 将 List 组装成 Tree
     *
     * @param list           原列表
     * @param rootValue      初级ID值
     * @param idGetter       主键获取器
     * @param pidGetter      父级ID获取器
     * @param childrenSetter 子级设置器
     * @param <T>            列表对象类型
     * @param <P>            主键类型
     * @return 父级为 rootValue 的列表
     */
    public static <T, P> List<T> listTree(Collection<T> list,
                                          P rootValue,
                                          Function<T, P> idGetter,
                                          Function<T, P> pidGetter,
                                          BiConsumer<T, List<T>> childrenSetter,
                                          Predicate<T> filter,
                                          Comparator<T> sorted) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        Stream<T> stream = sorted == null ? list.stream() : list.stream().sorted(sorted);
        stream = filter == null ? stream : stream.filter(filter);
        Map<P, List<T>> group = stream.collect(Collectors.groupingBy(pidGetter));
        list.forEach(v -> childrenSetter.accept(v, group.getOrDefault(idGetter.apply(v), Collections.emptyList())));
        return group.getOrDefault(rootValue, Collections.emptyList());
    }

    /**
     * 两个集合联合，a + b
     *
     * @param a 集合
     * @param b 集合
     * @return 集合
     */
    public static <T> List<T> concat(List<T> a, List<T> b) {
        if (CollectionUtils.isEmpty(a)) {
            return b;
        }
        if (CollectionUtils.isEmpty(b)) {
            return a;
        }
        a.addAll(b);
        return a;
    }

    /**
     * Map 转换
     *
     * @param map              MAP
     * @param transferFunction 转换函数
     * @param <K>              键类型
     * @param <V>              原来的值类型
     * @param <O>              新的值类型
     * @return 新map
     */
    public static <K, V, O> Map<K, O> transfer(Map<K, V> map, BiFunction<K, V, O> transferFunction) {
        if (CollectionUtils.isEmpty(map)) {
            return Collections.emptyMap();
        }
        return map.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, v -> transferFunction.apply(v.getKey(), v.getValue())));
    }

    /**
     * 单一值的列表，如果 value == null 返回空列表
     *
     * @param value 值
     * @return 不可变列表
     */
    public static <T> List<T> singletonList(T value) {
        return value == null ? Collections.emptyList() : Collections.singletonList(value);
    }

}
